package datatableaux.rules;

import java.util.HashSet;

import datatableaux.*;
import entities.*;
import entities.concept.*;
import entities.role.Role;

public class DataSomeRule {

	
	ExistsConcept nextExp;
	DataCompletion dc;
	DataBranching br;
	
	public DataSomeRule(DataCompletion dc) {
		super();
		this.dc = dc;
		this.br = this.dc.getCurrentBranching();
	}

	/**
	 * Given any individual n, check if any other individual that has an order < that of n, has the same label as n
	 * Consequence: exists rule will be blocked for this n.
	 * @return
	 */
	public boolean labelSeenBefore(Individual n){
		//for(Individual nn:Individual.getAllIndividuals().values()){
		for(Individual nn:this.dc.getInitABox().getABoxIndividuals()){
			if(nn.getOrder() < n.getOrder() && nn.getLabels().containsAll(n.getLabels())
					&& n.getLabels().containsAll(nn.getLabels())){
				return true;
			}
		}
		return false;
	}

	public boolean isApplicable(Individual n){
		boolean app = false;
		//only consider unexpanded labels
		HashSet<Concept> unexp = new HashSet<Concept> ();
		unexp.addAll(n.getLabels());
		unexp.removeAll(n.getExpandedLabels());
		if(unexp.size()<1){
			return false;
		}
		for(Concept c : unexp){
			if(c instanceof ExistsConcept){
				ExistsConcept ec = (ExistsConcept) c;
				Role r = ec.getRole();
				Concept filler = ec.getFiller();
				if(n.getSuccessors(r) != null ){
					app = true;
					for(Individual nn : n.getSuccessors(r)){
						app &= !nn.getLabels().contains(filler);				
					}
					if(app) {
						//blocking strategy, new!
						if(this.labelSeenBefore(n)){
							//block this rule
							app = false;
							continue;
						}else{
							this.nextExp = ec;
							return app;
						}
					}
				}else{
					if(this.labelSeenBefore(n)){
						app = false;
						continue;
					}else{
						app = true;
						this.nextExp = ec;
						return app;
					}
					
				}
			}
			
		}
		return app;
	}
	
	
	public boolean applyRule(Individual n){
		boolean suc = false;
		//System.out.println(this.nextExp);
		Role r = this.nextExp.getRole();
		Concept filler = this.nextExp.getFiller();
		//first check if r has a domain to add, if so, n should be re-checked!!!
		if(r.getDomain()!=null){
			n.addLabels(r.getDomain());
			if(DataBranchChanges.getRecordingStatus()){
				br.getBranchChanges().addToLabel(n, r.getDomain());
			}
			suc = true;
		}
		//create a new successor and apply labels.
		Individual temp = Individual.getAnonIndividual();
		temp.addLabels(filler);
		//add range
		if(r.getRange() != null){
			temp.addLabels(r.getRange());
			if(DataBranchChanges.getRecordingStatus()){
				br.getBranchChanges().addToLabel(temp, r.getRange());
			}
		}
		n.addSucessors(r, temp);
		n.addExpandedLabels(this.nextExp);
		//successor always added to the head of queue
		dc.addToQueue(temp, DataCompletion.INQUEUEFIRST);
		if(DataBranchChanges.getRecordingStatus()){
			br.getBranchChanges().addPotentialQueueInds(temp);
			br.getBranchChanges().addRoleRelations(n, r,temp);
			br.getBranchChanges().addToExpandedLabel(n, this.nextExp);
		}
		//if this concept is expanded after any other already expanded forall concepts....
		suc |= n.restoreForallConceptToExpandedLabels(r);
		return suc;
	}
	
}
